#include "hikari.h"

HObj::HObj(ISceneNode*node){
	this->node=node;
	animationData=NULL;
	updateable=false;
	rigidBody=NULL;
}


HObj::~HObj(){
	node->removeAll();
	node->remove();
}

void HObj::setRigidBodyPosition(vector3df&position){
	if(rigidBody!=NULL){
		btVector3 vector(position.X, position.Y, position.Z);
		btMotionState*mste=rigidBody->getMotionState();
		btTransform tr; 
		tr=rigidBody->getWorldTransform();
		tr.setOrigin(vector);
		rigidBody->setWorldTransform(tr);
		mste->getWorldTransform(tr);
		tr.setOrigin(vector);
		mste->setWorldTransform(tr);	
	}
}

void HObj::moveRigidBody(vector3df&pos){
	setRigidBodyPosition(getRigidBodyPosition()+pos);
}

void HObj::moveRigidBodyX(float length){
	setRigidBodyPosition(getRigidBodyPosition()+getRotation().rotationToDirection(vector3df(length,0,0)));
}

void HObj::moveRigidBodyY(float length){
	setRigidBodyPosition(getRigidBodyPosition()+getRotation().rotationToDirection(vector3df(0,length,0)));
}

void HObj::moveRigidBodyZ(float length){
	setRigidBodyPosition(getRigidBodyPosition()+getRotation().rotationToDirection(vector3df(0,0,length)));
}

void HObj::turnRigidBodyX(float angle){
	turnRigidBody(vector3df(1,0,0), angle);
}

void HObj::turnRigidBodyY(float angle){
	turnRigidBody(vector3df(0,1,0), angle);
}

void HObj::turnRigidBodyZ(float angle){
	turnRigidBody(vector3df(0,0,1), angle);
}

btQuaternion turnQuaternion(btQuaternion&quat, vector3df&axis, float angle){
	btQuaternion q(btVector3(axis.X,axis.Y,axis.Z), angle);
	return quat*q;
}

void HObj::turnRigidBody(vector3df&axis, float angle){
	if(rigidBody==NULL){
		Utils::errorLog(L"Object has no rigid body attached");
	}
	btMotionState*mste=rigidBody->getMotionState();
	btTransform tr; 
	btQuaternion rotation;

	tr=rigidBody->getWorldTransform();
	rotation=tr.getRotation();
	rotation=turnQuaternion(rotation, axis,DEGTORAD*angle);
	tr.setRotation(rotation);
	rigidBody->setWorldTransform(tr);
	
	
	mste->getWorldTransform(tr);
	rotation=tr.getRotation();
	rotation=turnQuaternion(rotation, axis,DEGTORAD*angle);
	tr.setRotation(rotation);
	mste->setWorldTransform(tr);
}


vector3df HObj::getRigidBodyPosition(){
	btTransform tr=rigidBody->getWorldTransform();
	btVector3&orig=tr.getOrigin();
	return vector3df(orig.getX(),orig.getY(),orig.getZ());
}

bool HObj::useAnimationFromNode(HObj*object){
	IAnimatedMeshSceneNode*sourcenode=dynamic_cast<IAnimatedMeshSceneNode*>(object->getInternalNode());
	if(sourcenode==NULL){
		Utils::errorLog(L"Source object is not IAnimatedMeshSceneNode. Cannot make \"useAnimationFrom\"");
		return false;
	}

	IAnimatedMeshSceneNode*destnode=dynamic_cast<IAnimatedMeshSceneNode*>(getInternalNode());
	if(destnode==NULL){
		Utils::errorLog(L"Object is not IAnimatedMeshSceneNode. Cannot make \"useAnimationFrom\"");
		return false;
	}

	ISkinnedMesh*sourceMesh=dynamic_cast<ISkinnedMesh*>(sourcenode->getMesh());
	if(sourceMesh==NULL){
		Utils::errorLog(L"Mesh in source object is not ISkinnedMesh. Cannot make \"useAnimationFrom\"");
		return false;
	}

	ISkinnedMesh*destMesh=dynamic_cast<ISkinnedMesh*>(destnode->getMesh());
	if(destMesh==NULL){
		Utils::errorLog(L"Mesh is not ISkinnedMesh. Cannot make \"useAnimationFrom\"");
		return false;
	}

	destMesh->useAnimationFrom(sourceMesh);
	setAnimationData(object->getAnimationData());
	return true;
}

hComponent*HObj::getComponent(wstring&componentName){
	int count=components.size();
	for(int i=0;i<count;i++){
		if(Utils::equal(componentName, components[i]->getName())){
			return components[i];
		}
	}

	return NULL;
}

hComponent*HObj::getRenderComponent(wstring&componentName){
	int count= renderComponents.size();
	for(int i=0;i<count;i++){
		if(Utils::equal(componentName, renderComponents[i]->getName())){
			return renderComponents[i];
		}
	}

	return NULL;
}

hComponent*HObj::getRenderComponent(wchar_t*componentName){
	return getRenderComponent(wstring(componentName));
}

void HObj::addComponent(hComponent*component){
	if(component==NULL || Utils::isEmpty(component->getName())){
		Utils::errorLog(L"Try to add empty component to object");
		return;
	}
	if(getComponent(component->getName())!=NULL){
		wstring message=wstring(L"WARNING: Object [")+getName()+L"] already has component with name ["+component->getName()+L"]";
		Utils::errorLog(message);
	}
	components.push_back(component);
}

void HObj::addRenderComponent(hComponent*component){
	if(component==NULL || Utils::isEmpty(component->getName())){
		Utils::errorLog(L"Try to add empty component to object");
		return;
	}
	if(getRenderComponent(component->getName())!=NULL){
		wstring message=wstring(L"WARNING: Object [")+getName()+L"] already has component with name ["+component->getName()+L"]";
		Utils::errorLog(message);
	}
	renderComponents.push_back(component);
	setRenderUpdatealbe(true);
}

vector<hComponent*>& HObj::getComponentList(){
	return components;
}

vector<hComponent*>& HObj::getRenderComponentList(){
	return renderComponents;
}

bool HObj::enableComponent(wstring&componentName, bool enable){
	hComponent*component=getComponent(componentName);
	if(component==NULL){
		wstring message=wstring(L"WARNING: Object [")+getName()+L"] does not have component ["+componentName+L"] to enable it\n";
		Utils::errorLog(message);
		return false;
	}
	component->setEnabled(enable);
	return true;
}

bool HObj::isComponentEnabled(wstring&componentName){
	hComponent*component=getComponent(componentName);
	if(component==NULL){
		wstring message=wstring(L"WARNING: Object [")+getName()+L"] does not have component ["+componentName+L"] to check if it is enabled\n";
		Utils::errorLog(message);
		return false;
	}
	return component->isEnabled();
}

void HObj::setPosition(vector3df position){
	node->setPosition(position);
}

void HObj::setRotation(vector3df rotation){
	node->setRotation(rotation);
}

void HObj::setScale(vector3df scale){
	node->setScale(scale);
}

vector3df HObj::getPosition(){
	return node->getPosition();
}

vector3df HObj::getRotation(){
	return node->getRotation();
}

vector3df HObj::getScale(){
	return node->getScale();
}

void HObj::move(vector3df offset){
}

void HObj::moveX(float offset){
	vector3df pos=node->getPosition()+node->getRotation().rotationToDirection(vector3df(offset, 0, 0));
	node->setPosition(pos);
}

void HObj::turnX(float offset){
	node->setRotation(node->getRotation()+vector3df(offset,0,0));
}

void HObj::turnY(float offset){
	node->setRotation(node->getRotation()+vector3df(0,offset,0));
}

void HObj::turnZ(float offset){
	node->setRotation(node->getRotation()+vector3df(0,0,offset));
}

void HObj::moveY(float offset){
	vector3df pos=node->getPosition()+node->getRotation().rotationToDirection(vector3df(0, offset, 0));
	node->setPosition(pos);
}

void HObj::moveZ(float offset){
	vector3df origPos=node->getPosition();
	vector3df rotation=node->getRotation();
	vector3df rotationPos=rotation.rotationToDirection(vector3df(0, 0, offset));
	vector3df pos=origPos+rotationPos;
	node->setPosition(pos);
}

void HObj::animate(const wchar_t*animationTrackName){
	animate(wstring(animationTrackName));
}
void HObj::animate(wstring&animationTrackName){
	IAnimatedMeshSceneNode*tnode=dynamic_cast<IAnimatedMeshSceneNode*>(node);
	if(tnode==NULL){
		Utils::errorLog(wstring(L"3dObject name[")+getName()+L"] is not animated object");
		return;
	}
	AnimationTrack*track=animationData->getAnimationTrack(animationTrackName);
	if(track==NULL){
		Utils::errorLog(wstring(L"3dObject name[")+getName()+L"] does not contain animation track ["+animationTrackName+L"%s]");
		return;
	}

	tnode->setAnimationSpeed(track->getSpeed());
	tnode->setCurrentFrame((f32)track->getStartFrame());
	tnode->setFrameLoop(track->getStartFrame(), track->getEndFrame());
}